﻿<template>
  <!-- ws的弹窗 -->
  <el-dialog v-drag :title = 'wsDialogInfo.dialogTitle' :visible.sync = 'wsDialogInfo.visibleDialog' width = '50%' :before-close = 'resetForm'
  :close-on-press-escape = 'false' :close-on-click-modal = 'false' append-to-body >
    <el-form label-position = 'top' element-loading-spinner = "el-icon-loading" v-loading='loading' :element-loading-text='loadtext'>
      <el-form-item :label = 'wsInfo.wsMsg'>
        <!-- 确认框 -->
        <el-radio-group v-model = 'wsInfo.messageInputInfo' v-if = "wsInfo.wsMsgType === 'Confirm'">
          <el-radio :label = "true">是</el-radio>
          <el-radio :label = "false">否</el-radio>
        </el-radio-group>
        <!-- 普通输入框 -->
        <el-input v-else-if = "wsInfo.wsMsgType === 'Input'" v-model = 'wsInfo.messageInputInfo' :placeholder = 'wsInfo.wsMsg'></el-input>
        <!-- 多行输入框 -->
        <el-input v-else-if = "wsInfo.wsMsgType === 'Text'" type = "textarea" autosize v-model = 'wsInfo.messageInputInfo' :placeholder = 'wsInfo.wsMsg'></el-input>
        <!-- 需要上传图片/文件时 -->
        <el-upload v-else-if = "wsInfo.wsMsgType === 'Confirm_Pic' || wsInfo.wsMsgType === 'UploadFile'" ref = 'upload' :action = 'actionUrl' :limit = 'limit' :auto-upload = "true" :file-list = 'fileList' drag
        :on-exceed = 'onExceed' :before-remove = 'removeUpload' :http-request = "submitUpload">
          <i class = "el-icon-upload"></i>
          <div class = "el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        </el-upload>
        <!-- 需要上传图片/文件时(二进制上传) -->
        <el-upload v-else-if = "wsInfo.wsMsgType === 'UploadFileBinary'"
        ref = 'upload' :action = 'actionUrl' :limit = 'limit' :auto-upload = "true" :file-list = 'fileList' drag
        :on-exceed = 'onExceed' :before-remove = 'removeUpload' :http-request = "submitUpload_buffer">
          <i class = "el-icon-upload"></i>
          <div class = "el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        </el-upload>
        <!-- 需要上传文件夹 -->
        <div v-else-if = "wsInfo.wsMsgType === 'UploadDirectory' || wsInfo.wsMsgType === 'ReplyPercentDir' || wsInfo.wsMsgType === 'ContinueDir' || wsInfo.wsMsgType === 'RecievedFileInfoThenContent'"
        style = 'text-align: center'>
          <div style="padding:20px 0 20px 0;text-align:left" >
            <el-button icon="el-icon-folder-opened" type="primary" @click="btnChange">点击上传</el-button>
            <input type="file" id="file" hidden @change="fileChange" webkitdirectory>
          </div>
          <el-table :data = "dir_files" stripe max-height="500">
            <el-table-column fixed align="center" label="路径" prop="file_path" min-width="60%"></el-table-column>
            <el-table-column align="center" label="进度">
              <template slot-scope = "scope">
              <el-progress :percentage="scope.row.percentage" :color="scope.row.mcolor"></el-progress>
              </template>
            </el-table-column>
          </el-table>
        </div>
        <!-- 下拉单选 -->
        <el-select v-else-if = "wsInfo.wsMsgType === 'Select'" v-model = 'wsInfo.messageInputInfo' :placeholder = 'wsInfo.wsMsg'>
          <el-option v-for = 'item in wsInfo.wsSelectData' :key = 'item.code' :value = 'item.code' :label = 'item.value'></el-option>
        </el-select>
        <!-- 下拉多选 -->
        <el-select v-else-if = "wsInfo.wsMsgType === 'Multi_Select'" v-model = 'wsInfo.messageInputInfo_array'
        :placeholder = 'wsInfo.wsMsg' multiple collapse-tags>
          <el-option v-for = 'item in wsInfo.wsSelectData' :key = 'item.code' :value = 'item.code' :label = 'item.value'></el-option>
        </el-select>
        <!-- 进度条 -->
        <div v-else-if = "wsInfo.wsMsgType === 'ProgressBar'" style = 'text-align: center'>
          <el-progress type = "circle" :percentage = "progressLoadingNum"></el-progress>
        </div>
        <!-- 二进制文件上传进度条 -->
        <div v-else-if = "wsInfo.wsMsgType === 'ReplyPercent'" style = 'text-align: center'>
          <el-progress type = "circle" :percentage = "progressLoadingNum_arrayBuffer"></el-progress>
        </div>
        <!-- 图片或文件下载时 -->
        <div v-else-if = "wsInfo.wsMsgType === 'File_Base64_ProgressBar' || wsInfo.wsMsgType === 'Pic_Base64_ProgressBar'" style = 'text-align: center'>
          <el-progress type = "circle" :percentage = "downloadInfo.progressNum"></el-progress>
        </div>
        <!-- Form -->
        <div :style = "formUI.divStyle"  v-else-if = "wsInfo.wsMsgType === 'Form'">
          <div>
            <el-row class="grid-content" v-for = "(row, index) in formUI.matrixArray" :key = "'wsformrow_' + index">
              <div v-for = "col in row" :key = "col.dataIndex">
                <el-col :span="col.titleSpan" class="el-col title-col">
                  <span>{{formUI.cells[col.dataIndex].Title}}</span>
                </el-col>
                <el-col :span="col.colSpan">
                  <WS-Cell :wscontrol = "formUI.cells[col.dataIndex].wscontrol" :cellitem = "formUI.cells[col.dataIndex]"></WS-Cell>
                </el-col>
              </div>
            </el-row>
          </div>
        </div>
      </el-form-item>
      <el-form-item class = 'form_noLeftMargin' v-if = "wsInfo.wsMsgType !== 'ReplyPercent' && wsInfo.wsMsgType !== 'File_Base64_ProgressBar' && wsInfo.wsMsgType !== 'Pic_Base64_ProgressBar' && wsInfo.wsMsgType !== 'ProgressBar'
      && wsInfo.wsMsgType !== 'ReplyPercentDir' && wsInfo.wsMsgType !== 'UploadDirectory' && wsInfo.wsMsgType !== 'ContinueDir' && wsInfo.wsMsgType !== 'RecievedFileInfoThenContent'">
        <el-button type = 'info' @click = "resetForm" v-if = "wsInfo.wsMsgType === 'Confirm'">取 消</el-button>
        <el-button type = "primary" @click = "submitForm">确 定</el-button>
      </el-form-item>
    </el-form>
  </el-dialog>
</template>
<style lang = 'scss' scoped>
  .el-row {
    margin-bottom: 10px;
    &:last-child {
      margin-bottom: 0;
    }
  }
  .el-col {
    border-radius: 4px;
  }
  .title-col {
    padding-left: 5px;
  }
  .grid-content {
    border-radius: 4px;
    min-height: 36px;
  }
  .bg-purple-dark {
    background: #99a9bf;
  }
  .bg-purple {
    background: #d3dce6;
  }
  .bg-purple-light {
    background: #e5e9f2;
  }
</style>
<script>
import WSCell from '@/components/WebSocketComponents/WebSocketFormControl.vue'
export default {
  // 需要三个参数
  // 1、wsDialog-弹窗打开或关闭的变量
  // 2、wsTitle-本次ws连接的主题
  // 3、wsApiRouter-本次ws连接的地址
  props: ['wsDialog', 'wsTitle', 'wsApiRouter'],
  components: { WSCell },
  data () {
    return {
      // ws弹窗相关
      wsDialogInfo: {
        visibleDialog: false,
        dialogTitle: ''
      },
      // ws连接以及返回信息相关
      wsInfo: {
        wsObj: null,
        wsUrl: '',
        messageInputInfo: '',
        // 多选时
        messageInputInfo_array: [],
        wsMsgType: '',
        wsMsg: '',
        wsSelectData: null
      },
      // 类型为progressBar时
      progressLoadingNum: 0,
      progressLoadingNum_arrayBuffer: 0, // 二进制上传的进度条
      // 上传相关
      actionUrl: `${$URL.IMG_UPLOAD_URL}`,
      fileList: [],
      fileReader: '',
      limit: 1,
      // 文件或者图片下载时
      downloadInfo: {
        totalCount: 0,
        currentCount: 0,
        progressNum: 0,
        base64Str: '',
        fileInfo: null
      },
      dir_files: [{
        file_path: '',
        percentage: 10,
        mcolor: '#409eff'
      }],
      dir_fileobjs: [],
      formUI: {
        divStyle: 'width: 98%; text-align: left;padding-top:5px;height: 500px;overflow-y:auto',
        layout: 'Default',
        matrixArray: [[{
          titleSpan: 2,
          colSpan: 22,
          dataIndex: 0
        }]],
        cells: [{
          Title: '姓名',
          Name: 'n',
          Value: '',
          UI: 'Input',
          IsReadOnly: false,
          IsEnable: true,
          UIData: null,
          wscontrol: false,
          isValid: true,
          validErr: ''
        }],
        data: {}
      },
      loading: false,
      loadtext: '请稍后'
    }
  },
  mounted () {
    if (!window.FileReader) {
      this.$message({
        message: '您的浏览器不支持 FileReader API',
        type: 'error'
      })
    } else {
      this.fileReader = new FileReader()
    }
    this.wsDialogInfo.visibleDialog = this.wsDialog
    if (this.wsDialog) {
      this.initComponent()
    }
  },
  methods: {
    // 初始化页面信息
    initComponent () {
      if (!this.wsApiRouter) {
        this.$message({
          message: '没有获取到WebSocket连接的地址',
          type: 'error',
          duration: 0
        })
        return
      }
      // 获取websocket连接的地址
      let baseUrl = ''
      if ($URL.CENTER_API) {
        baseUrl = $URL.CENTER_API.replace('http', 'ws')
      } else {
        let host = window.location.host
        baseUrl = 'ws://' + host
      }
      this.wsInfo.wsUrl = baseUrl + this.wsApiRouter
      // 弹窗的标题
      this.wsDialogInfo.dialogTitle = this.wsTitle
      // 初始化下载相关的信息
      this.fileList = []
      // 类型为progressBar时的信息
      this.progressLoadingNum = 0
      this.progressLoadingNum_arrayBuffer = 0
      // 上传文件夹
      this.dir_files = []
      // 下载时的相关信息
      this.downloadInfo = {
        totalCount: 0,
        currentCount: 0,
        progressNum: 0,
        base64Str: '',
        fileInfo: null
      }
      // loading
      this.closeLoading()
      // 进行webSocket连接
      this.createWebSocket(this.wsInfo.wsUrl)
    },
    renderFormUI () {
      this.formUI.divStyle = 'width: 98%; text-align: left;padding-top:5px;overflow-y:auto;height: ' + (window.outerHeight - 300) + 'px'
    },
    // 创建webSocket连接
    createWebSocket (url) {
      if ('WebSocket' in window) {
        if (this.wsInfo.wsObj) {
          this.wsInfo.wsObj.close()
        }
        try {
          // this.wsInfo.wsObj = new WebSocket(url)
          let token = sessionStorage.getItem('token')
          this.wsInfo.wsObj = new WebSocket(url, [token])
          // 连接成功后，初始化，websocket相关的操作
          this.initWsMethods()
        } catch (err) {
          console.log(err)
        }
      } else {
        this.$message({
          message: '您的浏览器不支持WebSocket',
          type: 'error',
          duration: 0
        })
      }
    },
    // 初始化WebSocket的相关方法
    initWsMethods () {
      // 监听socket连接
      this.wsInfo.wsObj.onopen = this.wsOpen
      // 监听socket消息
      this.wsInfo.wsObj.onmessage = this.wsGetMessage
      // 监听scoket关闭消息
      this.wsInfo.wsObj.onclose = this.wsClose
      // 监听socket错误信息
      this.wsInfo.wsObj.onerror = this.wsError
    },
    // 连接时
    wsOpen () {
      console.log('socket连接成功')
    },
    // 断开时
    wsClose () {
      console.log('socket断开')
      // 下载时的相关信息
      this.downloadInfo = {
        totalCount: 0,
        currentCount: 0,
        progressNum: 0,
        base64Str: '',
        fileInfo: null
      }
      this.closeLoading()
      this.clearData()
      this.$emit('webSocketDialogClosed')
    },
    // 异常时
    wsError () {
      this.$message({
        message: 'WebSocket连接出错',
        type: 'error',
        duration: 3000
      })
    },
    // 获取信息时
    wsGetMessage (msg) {
      // 对服务端返回的数据进行处理
      if (msg.data && msg.data.indexOf('{') !== -1) {
        // 一般而言服务端返回的数据格式是字符串(JSON格式)
        let dataObj = JSON.parse(msg.data)
        console.log(dataObj)
        if (dataObj.code === 'success') {
          // 信息的类别
          this.wsInfo.wsMsgType = dataObj.ws_msg_type
          // 客户端需要发送的信息的内容
          this.wsInfo.messageInputInfo = ''
          // 多选时，值为数组形式
          this.wsInfo.messageInputInfo_array = []
          // 服务端返回的信息的内容
          this.wsInfo.wsMsg = dataObj.msg
          // 返回的下拉框的数据集
          this.wsInfo.wsSelectData = dataObj.data ? dataObj.data : []
          // 需要根据信息的类别，判断应该执行什么样的操作
          if (dataObj.ws_msg_type === 'Normal' || dataObj.ws_msg_type === 'Alert') {
            this.$message({
              message: dataObj.msg,
              type: 'info',
              showClose: true,
              duration: 10000
            })
          } else if (dataObj.ws_msg_type === 'ProgressBar') {
            // 当为进度条时
            if (dataObj.data && dataObj.data.current_val && dataObj.data.max_val) {
              let precentage = parseInt(dataObj.data.current_val / dataObj.data.max_val * 100)
              this.progressLoadingNum = precentage > 100 ? 100 : precentage
            } else {
              this.progressLoadingNum = 0
            }
          } else if (dataObj.ws_msg_type === 'ReplyPercent') {
            // 当为进度条时_二进制上传
            if (dataObj.data && dataObj.data.current_val && dataObj.data.max_val) {
              let precentage = parseInt(dataObj.data.current_val / dataObj.data.max_val * 100)
              this.progressLoadingNum_arrayBuffer = precentage > 100 ? 100 : precentage
            } else {
              this.progressLoadingNum_arrayBuffer = 0
            }
          } else if (dataObj.ws_msg_type === 'ReplyPercentDir') {
            // 当为进度条时_文件夹上传
            if (dataObj.data && dataObj.data.current_val && dataObj.data.max_val && dataObj.data.current_index >= 0) {
              let precentage = parseInt(dataObj.data.current_val / dataObj.data.max_val * 100)
              let index = dataObj.data.current_index
              this.dir_files[index].percentage = precentage > 100 ? 100 : precentage
            }
          } else if (dataObj.ws_msg_type === 'ContinueDir') {
            // 当为继续上传下一个文件
            if (dataObj.data && dataObj.data.current_index >= 0) {
              if (this.dir_fileobjs && this.dir_fileobjs.length >= dataObj.data.current_index) {
                this.sendFileInfo4Dir(this.dir_fileobjs[dataObj.data.current_index + 1])
              }
            }
          } else if (dataObj.ws_msg_type === 'RecievedFileInfoThenContent') {
            // 当为继续上传下一个文件
            if (dataObj.data && dataObj.data.current_index >= 0) {
              if (this.dir_fileobjs && this.dir_fileobjs.length >= dataObj.data.current_index) {
                this.sendFileContent4Dir(this.dir_fileobjs[dataObj.data.current_index])
              }
            }
          } else if (dataObj.ws_msg_type === 'Text') {
            // 多行文本输入时
            if (dataObj.data) {
              this.wsInfo.messageInputInfo = dataObj.data
            }
          } else if (dataObj.ws_msg_type === 'File_Base64') {
            // 文件下载时
            if (dataObj.data && dataObj.data.file) {
              let content = decodeURIComponent(dataObj.data.file)
              let blobContent = this.toBlob(content, dataObj.data.filetype)
              this.downloadblob(blobContent, dataObj.data.filename)
            }
          } else if (dataObj.ws_msg_type === 'Console') {
            // 当为操作日志输出时，展示在父弹窗页面
            this.$emit('getConsoleInfoSuccess', this.wsInfo.wsMsg)
          } else if (dataObj.ws_msg_type === 'File_Base64_ProgressBar' || dataObj.ws_msg_type === 'Pic_Base64_ProgressBar') {
            // 文件或图片下载需要显示进度时
            if (dataObj.data) {
              if (dataObj.data.progress_max && dataObj.data.step === 'start') {
                // 开始下载时
                this.$set(this.downloadInfo, 'totalCount', dataObj.data.progress_max)
                this.$set(this.downloadInfo, 'currentCount', 0)
                this.$set(this.downloadInfo, 'progressNum', 0)
                this.$set(this.downloadInfo, 'base64Str', '')
                this.$set(this.downloadInfo, 'fileInfo', null)
              }
              if (dataObj.data.file_frame && dataObj.data.filename && dataObj.data.filelength && dataObj.data.filetype) {
                // 下载时
                let current = this.downloadInfo.currentCount + 1
                this.$set(this.downloadInfo, 'currentCount', current)
                let precentage = parseInt(this.downloadInfo.currentCount / this.downloadInfo.totalCount * 10000) / 100
                precentage = precentage > 100 ? 100 : precentage
                this.$set(this.downloadInfo, 'progressNum', precentage)
                let base64StrLong = this.downloadInfo.base64Str + dataObj.data.file_frame
                this.$set(this.downloadInfo, 'base64Str', base64StrLong)
                this.$set(this.downloadInfo, 'fileInfo', dataObj.data)
              }
              if (dataObj.data.step === 'end') {
                // 下载完成时
                this.$set(this.downloadInfo, 'totalCount', dataObj.data.progress_max)
                this.$set(this.downloadInfo, 'currentCount', this.downloadInfo.totalCount)
                this.$set(this.downloadInfo, 'progressNum', 100)
                let content = decodeURIComponent(this.downloadInfo.base64Str)
                let blobContent = this.toBlob(content, this.downloadInfo.fileInfo.filetype)
                this.downloadblob(blobContent, this.downloadInfo.fileInfo.filename)
              }
            }
          } else if (dataObj.ws_msg_type === 'Form') {
            console.debug(dataObj.data)
            if (dataObj.data) {
              this.formUI.layout = dataObj.data.FormStyle
              this.formUI.cells = dataObj.data.Cells
              for (let i = 0; i < this.formUI.cells.length; i++) {
                this.formUI.cells[i].isValid = true
                this.formUI.cells[i].validErr = ''
              }
              let r = 0
              let c = 0
              if (this.formUI.layout === 'Grid2') {
                r = this.formUI.cells.length % 2 === 0 ? parseInt(this.formUI.cells.length / 2) : parseInt(this.formUI.cells.length / 2) + 1
                c = 2
              } else if (this.formUI.layout === 'Grid3') {
                r = this.formUI.cells.length % 3 === 0 ? parseInt(this.formUI.cells.length / 3) : parseInt(this.formUI.cells.length / 3) + 1
                c = 3
              } else {
                r = this.formUI.cells.length
                c = 1
              }
              this.formUI.matrixArray = []
              for (let i = 0; i < r; i++) {
                this.formUI.matrixArray[i] = []
                for (let j = 0; j < c; j++) {
                  let dIndex = i * c + j
                  if (this.formUI.cells.length <= dIndex) break
                  this.formUI.matrixArray[i][j] = {
                    titleSpan: 2,
                    colSpan: parseInt(24 / c) - 2,
                    rules: this.getRulesByUIType(this.formUI.cells[dIndex].UI),
                    dataIndex: dIndex
                  }
                }
              }
              this.renderFormUI()
              this.showWSControls(true)
            }
          }
        } else {
          if (dataObj.result) {
            // 如果是操作完成，给出相应的提示
            this.$message({
              message: dataObj.result.msg,
              type: dataObj.result.code === 'success' ? 'success' : 'warning',
              duration: 3000
            })
            if (dataObj.result.code === 'success') {
              this.closeWsMethod()
            }
          }
        }
      }
    },
    // 手动关闭webscoket的连接
    closeWsMethod () {
      if (this.wsInfo.wsObj && this.wsInfo.wsObj.readyState === 1) {
        this.wsInfo.wsObj.send('Close')
      } else {
        console.info('WebSocket连接已断开')
      }
      if (this.wsInfo.wsObj) {
        this.wsInfo.wsObj.close()
      }
      this.doLoading('关闭中')
    },
    clearData () {
      // 清除发送目录上传的相关数据
      this.clearSendDirData()
      // FormUI
      this.showWSControls(false)
    },
    getRulesByUIType (ui) {
      if (ui === 'EmailInput') {
        return [
          { type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }
        ]
      } else {
        return []
      }
    },
    // 点击确认按钮时
    submitForm () {
      if (this.wsInfo.wsMsgType === 'Multi_Select') {
        this.sendText(this.wsInfo.messageInputInfo_array.join(','))
      } else if (this.wsInfo.wsMsgType === 'Form') {
        let valid = true
        for (let i = 0; i < this.formUI.cells.length; i++) {
          if (this.formUI.cells[i].isValid === false) {
            valid = false
            break
          }
        }
        if (valid) {
          let msgobj = {}
          for (let i = 0; i < this.formUI.cells.length; i++) {
            let item = this.formUI.cells[i]
            msgobj[item.Name] = item.Value
          }
          // console.debug(msgobj)
          let msg = JSON.stringify(msgobj)
          this.sendText(msg)
        } else {
          return false
        }
      } else {
        this.sendText(this.wsInfo.messageInputInfo)
      }
    },
    // 点击取消按钮时
    resetForm () {
      this.$confirm('确定要放弃' + this.wsDialogInfo.dialogTitle + '的操作么?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        cancelButtonClass: 'el-button--info'
      }).then(() => {
        this.closeWsMethod()
      }).catch(() => {})
    },
    // 上传相关的方法-------------------上传相关
    // 文件超过最大上传个数时
    onExceed () {
      this.$message({
        message: '最多只能上传' + this.limit + '个文件',
        type: 'warning'
      })
    },
    // 上传文件移除
    removeUpload (file) {
      this.$confirm('确定要移除该文件么,请谨慎操作！', '提示', {
        showClose: false,
        showCancelButton: true,
        confirmButtonText: '确定',
        cancelButtonClass: 'el-button--info',
        cancelButtonText: '取消'
      }).then(() => {
        // 直接将展示的列表中移除
        if (this.fileList.length) {
          this.fileList.forEach((item, index) => {
            if (item.url === file.url) {
              this.fileList.splice(index, 1)
            }
          })
        }
        this.$message({
          message: '删除成功',
          type: 'success'
        })
      }).catch(() => {
      })
      // 返回false 表示放弃控件删除的操作---实际上是在服务端进行了删除，并且从fileList中移除了
      return false
    },
    // 上传文件的方法
    submitUpload (options) {
      let file = options.file
      let filename = file.name
      let fileLength = file.size
      let fileType = file.type
      if (file) {
        this.fileReader.readAsDataURL(file)
      }
      this.fileReader.onload = () => {
        let base64Str = this.fileReader.result
        // 获取上传文件、图片的json格式
        let messageObj = {
          filetype: fileType,
          filename: filename,
          filelength: fileLength,
          file: base64Str.split(',')[1]
        }
        this.wsInfo.messageInputInfo = JSON.stringify(messageObj)
        // 上传成功后，直接发送消息给ws
        this.sendText(this.wsInfo.messageInputInfo)
      }
    },
    // 上传文件的方法---二进制
    submitUpload_buffer (options) {
      let file = options.file
      let filename = file.name
      let fileLength = file.size
      let fileType = file.type
      let messageObj = {
        filetype: fileType,
        filename: filename,
        filelength: fileLength
      }
      this.wsInfo.messageInputInfo = JSON.stringify(messageObj)
      // 上传成功后，直接发送消息给ws
      this.sendText(this.wsInfo.messageInputInfo)
      if (file) {
        this.fileReader.readAsArrayBuffer(file)
      }
      this.fileReader.onload = (e) => {
        console.log(e)
        let arrayBufferStr = e.target.result
        this.sendBinary(arrayBufferStr, 256, 50, 200)
      }
    },
    // 下载文件的相关方法
    downloadblob (blobcontent, filename) {
      if ('msSaveOrOpenBlob' in navigator) {
        // Microsoft Edge and Microsoft Internet Explorer 10-11
        window.navigator.msSaveOrOpenBlob(blobcontent, filename)
      } else {
        // 创建隐藏的可下载链接
        var eleLink = document.createElement('a')
        eleLink.download = filename
        eleLink.style.display = 'none'
        // 字符内容转变成blob地址
        eleLink.href = URL.createObjectURL(blobcontent)
        // 触发点击
        document.body.appendChild(eleLink)
        eleLink.click()
        // 然后移除
        document.body.removeChild(eleLink)
      }
    },
    // 将base64装为文件
    toBlob (base64str, filetype) {
      let bytes = window.atob(base64str)
      let n = bytes.length
      let u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bytes.charCodeAt(n)
      }
      return new Blob([u8arr], {type: filetype})
    },
    // 上传文件夹 begin
    fileChange (e) {
      try {
        let fu = document.getElementById('file')
        if (fu == null) return
        this.dir_files = []
        this.dir_fileobjs = []
        let dirinfo = {
          filecount: fu.files.length
        }
        this.wsInfo.messageInputInfo = JSON.stringify(dirinfo)
        // 上传成功后，直接发送消息给ws
        if (this.wsInfo.wsObj && this.wsInfo.wsObj.readyState === 1) {
          this.wsInfo.wsObj.send(this.wsInfo.messageInputInfo)
        } else {
          this.$message({
            message: 'WebSocket连接已断开',
            type: 'warning',
            duration: 3000
          })
          return
        }
        this.dir_fileobjs = fu.files
        for (let i = 0; i < this.dir_fileobjs.length; i++) {
          let tableitem = {
            file_path: this.dir_fileobjs[i].webkitRelativePath,
            percentage: 0,
            mcolor: '#409eff'
          }
          this.dir_files.push(tableitem)
        }
        if (this.dir_fileobjs.length > 0) {
          this.sendFileInfo4Dir(this.dir_fileobjs[0])
        }
      } catch (error) {
        console.debug('choice dir err:', error)
        this.$message({
          message: '操作失败',
          type: 'error',
          duration: 3000
        })
      }
    },
    btnChange () {
      let file = document.getElementById('file')
      file.value = ''
      file.click()
    },
    sendFileInfo4Dir (file) {
      if (!file) return
      if (!this.wsInfo.wsObj || this.wsInfo.wsObj.readyState !== 1) {
        this.$message({
          message: 'WebSocket连接已断开',
          type: 'warning',
          duration: 3000
        })
        return
      }
      // 发送文件消息
      let messageObj = {
        filetype: file.type,
        filename: file.name,
        filelength: file.size,
        filepath: file.webkitRelativePath
      }
      this.wsInfo.messageInputInfo = JSON.stringify(messageObj)
      // 上传成功后，直接发送消息给ws
      if (this.wsInfo.wsObj && this.wsInfo.wsObj.readyState === 1) {
        this.wsInfo.wsObj.send(this.wsInfo.messageInputInfo)
      } else {
        this.$message({
          message: 'WebSocket连接已断开',
          type: 'warning',
          duration: 3000
        })
      }
    },
    sendFileContent4Dir (file) {
      if (!file) return
      this.fileReader.readAsArrayBuffer(file)
      this.fileReader.onload = (e) => {
        console.log(e)
        let arrayBufferStr = e.target.result
        this.sendBinary(arrayBufferStr)
      }
    },
    sendBinary (arrayb, buffer_size, frame_delay, block_delay) {
      let bs = buffer_size ? buffer_size * 1024 : 512 * 1024
      let startobj = {
        action: 'start',
        total_length: arrayb.byteLength
      }
      if (!this.sendText(JSON.stringify(startobj))) {
        console.info('发送start失败')
        return false
      }
      let endsend = () => {
        let endobj = {
          action: 'end',
          total_length: arrayb.byteLength
        }
        if (!this.sendText(JSON.stringify(endobj))) {
          console.info('发送end失败')
          return false
        }
      }
      let max_circle = arrayb.byteLength % bs === 0 ? parseInt(arrayb.byteLength / bs) : parseInt(arrayb.byteLength / bs) + 1
      if (!frame_delay) frame_delay = 100
      if (!block_delay) block_delay = 200
      let timeout = 10
      let myloop = (i) => {
        setTimeout(() => {
          let start = i * bs
          let end = 0
          end = arrayb.byteLength - start > 0 ? start + bs : arrayb.byteLength
          let sendbuffer = arrayb.slice(start, end)
          if (this.wsInfo.wsObj && this.wsInfo.wsObj.readyState === 1) {
            this.wsInfo.wsObj.send(sendbuffer)
          } else {
            this.$message({
              message: 'WebSocket连接已断开',
              type: 'warning',
              duration: 3000
            })
            return false
          }
          i++
          // 每10 frame为一个block，每个block间隔拉长为200ms，每frame之间间隔10ms
          if (i % 10 === 0) timeout = block_delay
          else timeout = frame_delay
          if (i < max_circle) myloop(i)
          else endsend.call(this)
        }, timeout)
      }
      myloop.call(this, 0)
    },
    sendText (txt) {
      if (this.wsInfo.wsObj && this.wsInfo.wsObj.readyState === 1) {
        this.wsInfo.wsObj.send(txt)
        return true
      } else {
        this.$message({
          message: 'WebSocket连接已断开',
          type: 'warning',
          duration: 3000
        })
        return false
      }
    },
    clearSendDirData () {
      this.dir_files = []
      this.dir_fileobjs = []
    },
    doLoading (msg) {
      this.loading = true
      if (msg) this.loadtext = msg
      else this.loadtext = '请稍后'
    },
    closeLoading () {
      this.loading = false
    },
    // 控制FormUI中的组件是否显示
    showWSControls (isshow) {
      for (var i = 0; i < this.formUI.cells.length; i++) {
        this.formUI.cells[i].wscontrol = isshow
      }
    }
  },
  destroyed () {
    this.closeWsMethod()
    // 销毁监听--关闭webscoket连接
    console.log('destoryed at ' + new Date())
  },
  watch: {
    wsDialog: {
      handler: function (val, oldVla) {
        this.wsDialogInfo.visibleDialog = val
        // FormUI component
        // this.formUI.wsFC = val
        this.showWSControls(val)
        if (val) {
          this.initComponent()
        }
      }
    }
  }
}
</script>
